/* 
 * Gneat (http://gneat.org)
 *
 * (C) Copyright 2011 and beyond - Claudio Stella, all rights reserved.
 *
 * This file is part of Gneat.
 *
 * Gneat is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (LGPL)
 * as published by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Gneat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * and the GNU General Public License, for completeness, along with Gneat.  
 * If not, see <http://www.gnu.org/licenses/>.
 */
package org.neatshell.gneat.client.presenter.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.neatshell.gneat.client.callback.CallbackListBoolean;
import org.neatshell.gneat.client.callback.CallbackListVoid;
import org.neatshell.gneat.client.handler.BlurHandler;
import org.neatshell.gneat.client.handler.ChangeHandler;
import org.neatshell.gneat.client.handler.CustomHandler;
import org.neatshell.gneat.client.handler.ErrorHandler;
import org.neatshell.gneat.client.handler.FocusHandler;
import org.neatshell.gneat.client.handler.Handler;
import org.neatshell.gneat.client.handler.LoadHandler;
import org.neatshell.gneat.client.handler.ScrollHandler;
import org.neatshell.gneat.client.handler.SubmitHandler;
import org.neatshell.gneat.client.handler.keyboard.KeyDownHandler;
import org.neatshell.gneat.client.handler.keyboard.KeyPressHandler;
import org.neatshell.gneat.client.handler.keyboard.KeyUpHandler;
import org.neatshell.gneat.client.handler.mouse.ClickHandler;
import org.neatshell.gneat.client.handler.mouse.DblClickHandler;
import org.neatshell.gneat.client.handler.mouse.MouseDownHandler;
import org.neatshell.gneat.client.handler.mouse.MouseMoveHandler;
import org.neatshell.gneat.client.handler.mouse.MouseOutHandler;
import org.neatshell.gneat.client.handler.mouse.MouseOverHandler;
import org.neatshell.gneat.client.handler.mouse.MouseUpHandler;
import org.neatshell.gneat.client.presenter.core.manipulation.Attributes.Attribute;
import org.neatshell.gneat.client.presenter.core.manipulation.Properties.Property;
import org.neatshell.gneat.client.presenter.core.manipulation.css.Css;
import org.neatshell.gneat.client.tool.MiscUtils;
import org.neatshell.gneat.client.tool.Strings;

public class PresenterList implements IPresenterList {
	IPresenterList   _previous = null;
	List<IPresenter> _items;

	public PresenterList(IPresenter... items) {
		_items = new ArrayList<IPresenter>();
		_add(items);
	}

	public PresenterList(IPresenterList list) {
		this(list.toArray());
	}
	
	private IPresenterList _add(IPresenter... items) {
		if (items != null) {
			for (IPresenter item : items) {
				if (item != null
					&& item.is()
					&& !_items.contains(item)) {
					_items.add(item);
				}
			}
		}
		return this;
	}

	private IPresenterList _add(IPresenterList list) {
		return list != null ? _add(list.toArray()) : this;
	}

	private IPresenterList _alternate(final boolean even) {
		final PresenterList alternate = (PresenterList) new PresenterList().push(this);
		each(new CallbackListVoid() {			
			@Override
			protected Void onFire(int index, IPresenter item) {
				if (even && index % 2 == 1) {
					alternate._add(item);
				}
				else if (!even && index % 2 == 0) {
					alternate._add(item);
				}
				return null;
			}
		});
		return alternate;
	}	

	@Override
	public IPresenterList add(Integer index, IPresenter... items) {
		if (items != null) {
			int l = length();
			IPresenter[] array = this.toArray();

			int c = 0;
			index = MiscUtils.getZeroBased(index, length());
			if (index >= 0) {
				for (IPresenter item : items) {
					if (item != null
						&& item.is()
						&& !_items.contains(item)) {
						_items.add(index + c++, item);
					}
				}
				if (length()>l) return push(new PresenterList(array).push(this.pop()));
			}
			else add(items);
		}
		return this;
	}

	@Override
	public IPresenterList add(Integer index, IPresenterList list) {
		return list != null ? add(index, list.toArray()) : this;
	}

	@Override
	public IPresenterList add(IPresenter... items) {
		if (items != null) {
			int l = length();
			IPresenter[] array = this.toArray();

			_add(items);

			if (length()>l) return push(new PresenterList(array).push(this.pop()));			
		}
		return this;
	}

	@Override
	public IPresenterList add(IPresenterList list) {
		return list != null ? add(list.toArray()) : this;
	}
	
	@Override
	public IPresenterList addClass(String... classNames) {
		for (IPresenter item : toArray()) item.addClass(classNames);
		return this;
	}

	@Override
	public IPresenterList andSelf() {
		return add(pop());
	}
	
	@Override
	public IPresenterList append(IPresenter... items) {
		return append(new PresenterList(items));
	}
	
	@Override
	public IPresenterList append(IPresenterList list) {
		IPresenterList clones = list.clone(true);
		if (first().is()) first().append(list);
		for (IPresenter item : neq(0).toArray())
			item.append(clones.clone(true));
		return this;
	}

	@Override
	public boolean are() {
		return length() == 0;
	}
	
	@Override
	public boolean are(IPresenter... items) {
		if (items != null) {
			for (IPresenter p : items) {
				// If at least one is not contained exit with false
				if (!_items.contains(p)) return false;
			}
			//else exit with true
			return true;
		}
		return false;
	}

	@Override
	public boolean are(IPresenterList list) {
		return list != null ? are(list.toArray()) : false;
	}
	
	@Override
	public IPresenterList attr(Attribute attr, String value) {
		for (IPresenter item : toArray()) item.attr(attr, value);
		return this;
	}
	
	@Override
	public IPresenterList attr(String attrName, String value) {
		for (IPresenter item : toArray()) item.attr(attrName, value);
		return this;
	}
	
	@Override
	public String attr(Attribute attr) {
		return first().attr(attr);
	}
	
	@Override
	public String attr(String attrName) {
		return first().attr(attrName);
	}
	
	@Override
	public IPresenterList blur(BlurHandler handler) {
		return on(handler);
	}
	
	@Override
	public IPresenterList blur() {
		for (IPresenter item : toArray()) item.blur();
		return this;
	}

	@Override
	public IPresenterList change(ChangeHandler handler) {
		return on(handler);
	}
	
	@Override
	public IPresenterList change() {
		for (IPresenter item : toArray()) item.change();
		return this;
	}
		
	@Override
	public IPresenterList children() {
		return children(0);
	}
	
	@Override
	public IPresenterList children(Integer nodeType) {
		PresenterList children = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) children._add(item.children(nodeType));
		return children;
	}
	
	@Override
	public IPresenterList click(ClickHandler handler) {
		return on(handler);
	}
	
	@Override
	public IPresenterList click() {
		for (IPresenter item : toArray()) item.click();
		return this;
	}

	@Override
	public IPresenterList clone() {
		PresenterList clones = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) clones._add(item.clone());
		return clones;
	}	
	
	@Override
	//TODO how work end() and andSelf() ???
	public IPresenterList clone(Boolean withDataAndEvents) {
		PresenterList clones = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) clones._add(item.clone(withDataAndEvents));
		return clones;
	}

	@Override
	public IPresenterList clone(Boolean withDataAndEvents, Boolean deepWithDataAndEvents) {
		PresenterList clones = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) clones._add(item.clone(withDataAndEvents, deepWithDataAndEvents));
		return clones;
	}

	@Override
	public IPresenterList css(Css name, String value) {
		for (IPresenter item : toArray()) item.css(name, value);
		return this;
	}

	@Override
	public IPresenterList css(String name, String value) {
		for (IPresenter item : toArray()) item.css(name, value);
		return this;
	}

	@Override
	public HashMap<String, Object> data() {
		return first().data();
	}
	
	@Override
	public Object data(String key) {
		return first().data(key);
	}
	
	@Override
	public IPresenterList data(String key, Object value) {
		for (IPresenter item : toArray()) item.data(key, value);
		return this;
	}
	
	@Override
	public IPresenterList dblclick(DblClickHandler handler) {
		return on(handler);
	}

	@Override
	public IPresenterList dblclick() {
		for (IPresenter item : toArray()) item.dblclick();
		return this;
	}

	@Override
	public IPresenterList detach() {
		for (IPresenter item : toArray()) item.detach();
		return this;
	}	
	
	@Override
	public IPresenterList each(CallbackListBoolean callback) {
		for (IPresenter item : toArray()) {
			Boolean ret = callback.fire(index(item), item);
			if (ret != null && !ret) return this;
		}
		return this;
	}
	
	@Override
	public IPresenterList each(CallbackListVoid callback) {
		for (IPresenter item : toArray()) callback.fire(index(item), item);
		return this;
	}


	@Override
	public IPresenterList empty() {
		for (IPresenter item : toArray()) item.empty();
		return this;
	}

	@Override
	public IPresenterList end() {
		return pop();
	}
	
	@Override
	public IPresenterList eq(Integer... indexes) {
		PresenterList eq = (PresenterList) new PresenterList().push(this);
		if (indexes != null) {
			for (Integer index : indexes) eq._add(get(index));
		}
		return eq;
	}

	@Override
	public IPresenterList error(ErrorHandler handler) {
		return on(handler);
	}
	
	@Override
	public IPresenterList error() {
		for (IPresenter item : toArray()) item.error();
		return this;
	}
	
	@Override
	public IPresenterList even() {
		return _alternate(true);
	}	
	
//	@Override
//	public IPresenterList filter(String... filters) {
//		IPresenterList filter = new PresenterList().push(this);		
//		for (IPresenter p : toArray()) if (p.is(filters)) filter.add(p);
//		return filter;
//	}
	
	@Override
	public IPresenterList filter(Integer nodeType) {
		PresenterList filter = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			if (item.is(nodeType)) {
				filter._add(item);
			}
		}
		return filter;
	}
	
	@Override
	public IPresenterList filter(CallbackListBoolean handler) {
		PresenterList filter = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			if (handler.fire(index(item), item)) {
				filter._add(item);
			}
		}
		return filter;
	}

	@Override
	public IPresenterList find(Integer nodeType) {
		PresenterList find = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			find._add(item.find(nodeType));
		}
		return find;
	}
	
	@Override
	public IPresenterList find() {
		return find(1);
	}
	
	@Override
	public IPresenter first() {
		return get(0);
	}
		
	@Override
	public IPresenterList focus(FocusHandler handler) {
		return on(handler);
	}

	@Override
	public IPresenterList focus() {
		for (IPresenter item : toArray()) item.focus();
		return this;
	}

	@Override
	public IPresenter get(Integer index) {
		index = MiscUtils.getZeroBased(index, _items.size());
		return (index >= 0) ? _items.get(index) : PresenterNull.get();
	}

	@Override
	public IPresenterList has(IPresenter... items) {
		PresenterList has = (PresenterList) new PresenterList().push(this);
		if (items != null) {
			for (IPresenter container : toArray()) {
				if (container.has(items)) has._add(container);
			}
		}
		return has;
	}

	@Override
	public IPresenterList has(IPresenterList list) {
		return (list != null) ? has(list.toArray()) : new PresenterList().push(this);
	}

	@Override
	public boolean hasAttr(Attribute... attrs) {
		return first().hasAttr(attrs);
	}

	@Override
	public boolean hasAttr(String... attrNames) {
		return first().hasAttr(attrNames);
	}

	@Override
	public boolean hasClass(String... classNames) {
		return first().hasClass(classNames);
	}
	
	@Override
	public IPresenterList height(String value) {
		for (IPresenter item : toArray()) item.height(value);
		return this;
	}

	@Override
	public IPresenterList hide() {
		for (IPresenter item : toArray()) item.hide();
		return this;
	}
		
	@Override
	public IPresenterList keydown(KeyDownHandler handler) {
		return on(handler);
	}

	@Override
	public IPresenterList keydown() {
		for (IPresenter item : toArray()) item.keydown();
		return this;
	}	

	@Override
	public IPresenterList keypress(KeyPressHandler handler) {
		return on(handler);
	}
	
	@Override
	public IPresenterList keypress() {
		for (IPresenter item : toArray()) item.keypress();
		return this;
	}	

	@Override
	public IPresenterList keyup(KeyUpHandler handler) {
		return on(handler);
	}

	@Override
	public IPresenterList keyup() {
		for (IPresenter item : toArray()) item.keyup();
		return this;
	}

	@Override
	public String id() {
		return first().id();
	}	
	
	@Override
	public int index(IPresenter item) {
		return _items.indexOf(item);
	}

	@Override
	public boolean is(IPresenter... items) {
		if (items != null) {
			for (IPresenter item : toArray()) {
				if (item.is(items)) return true;
			}
		}
		return false;
	}

	@Override
	public boolean is(IPresenterList list) {
		return list != null ? is(list.toArray()) : false;
	}
	
	@Override
	public IPresenter last() {
		return get(-1);
	}
	
	@Override
	public int length() {
		return _items.size();
	}
	
	@Override
	public IPresenterList load(LoadHandler handler) {
		return on(handler);
	}
	
	@Override
	public IPresenterList load() {
		for (IPresenter item : toArray()) item.load();
		return this;
	}
	
	@Override
	public IPresenterList mousedown(MouseDownHandler handler) {
		return on(handler);
	}

	@Override
	public IPresenterList mousedown() {
		for (IPresenter item : toArray()) item.mousedown();
		return this;
	}

	@Override
	public IPresenterList mousemove(MouseMoveHandler handler) {
		return on(handler);
	}

	@Override
	public IPresenterList mousemove() {
		for (IPresenter item : toArray()) item.mousemove();
		return this;
	}
	
	@Override
	public IPresenterList mouseout(MouseOutHandler handler) {
		return on(handler);
	}

	@Override
	public IPresenterList mouseout() {
		for (IPresenter item : toArray()) item.mouseout();
		return this;
	}	
	
	@Override
	public IPresenterList mouseover(MouseOverHandler handler) {
		return on(handler);
	}
	
	@Override
	public IPresenterList mouseover() {
		for (IPresenter item : toArray()) item.mouseover();
		return this;
	}
	
	@Override
	public IPresenterList mouseup(MouseUpHandler handler) {
		return on(handler);
	}
	
	@Override
	public IPresenterList mouseup() {
		for (IPresenter item : toArray()) item.mouseup();
		return this;
	}
	
	@Override
	public IPresenterList neq(Integer... indexes) {
//		IPresenterList neq = new PresenterList(toArray()).push(this);
		IPresenterList neq = new PresenterList().push(this);		
		for (IPresenter item : toArray()) {
			neq.toList().add(item);
		}
		
		if (indexes != null) {
			PresenterList excludelist = new PresenterList();
			for (Integer index : indexes) {
				int i = MiscUtils.getZeroBased(index, _items.size());
				if (i >= 0) excludelist._add(_items.get(i));
			}
			
			for (IPresenter excludeitem : excludelist.toArray()) {
				neq.toList().remove(excludeitem);
			}
		}
		return neq;		
	}
	
	@Override
	public IPresenterList next(Integer nodeType) {
		PresenterList next = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			next._add(item.next(nodeType));
		}
		return next;
	}
	
	@Override
	public IPresenterList next() {
		return next(1);
	}
	
	@Override
	public IPresenterList nextAll(Integer nodeType) {
		PresenterList nextAll = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			nextAll._add(item.nextAll(nodeType));
		}
		return nextAll;
	}
	
	@Override
	public IPresenterList nextAll() {
		return nextAll(1);
	}
	
	@Override
	public IPresenterList nextUntil(IPresenter until, Integer nodeType) {
		PresenterList nextUntil = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			nextUntil._add(item.nextUntil(until, nodeType));
		}
		return nextUntil;
	}

	@Override
	public IPresenterList nextUntil(IPresenter until) {
		return nextUntil(until, 1);
	}

	@Override
	public IPresenterList not(IPresenter... items) {
		PresenterList not = (PresenterList) new PresenterList().push(this);

		if (items != null) {
			for (IPresenter old : toArray()) {
				if (!old.is(items)) not._add(old);
			}
			return not;
		}
		//TODO WHAT IS THISSSS??? CHECK IT!
		return not.add(this);
	}

	@Override
	public IPresenterList not(IPresenterList list) {
		return list != null ? not(list.toArray()) : new PresenterList().add(this);
//		return list != null ? not(list.toArray()) : new PresenterList().push(this).add(this);
	}

	@Override
	public IPresenterList off(String event) {
		for (IPresenter item : toArray()) item.off(event);
		return this;
	}

	IPresenterList on(Handler handler) {
		//TODO WRITE THIS CODE		
//		for (IPresenter item : toArray()) ((Handler) handler).clone(item);
		return this;
	}
	
	@Override
	//TODO WRITE THIS CODE
	public IPresenterList on(CustomHandler handler) {
//		for (IPresenter item : toArray()) ((Handler) handler).clone(item);
		return this;
	}
	
	@Override
	public IPresenterList odd() {
		return _alternate(false);
	}
	
	@Override
	public IPresenterList parent() {
		PresenterList parent = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) parent._add(item.parent());
		return parent;
	}

	@Override
	public IPresenterList parents() {
		PresenterList parents = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) parents._add(item.parents());
		return parents;
	}
	
	@Override
	public IPresenterList parentsUntil(IPresenter until) {
		PresenterList parentsUntil = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			parentsUntil._add(item.parentsUntil(until));
		}
		return parentsUntil;
	}
	
	IPresenterList pop() {
	    return _previous != null ? _previous : new PresenterList();		
	}
	
	@Override
	public IPresenterList prepend(IPresenter... items) {
		return prepend(new PresenterList(items));
	}
	
	@Override
	public IPresenterList prepend(IPresenterList list) {
		IPresenterList clones = list.clone(true);
		if (first().is()) {
			first().prepend(list);
		}
		for (IPresenter item : neq(0).toArray()) {
			item.prepend(clones.clone(true));			
		}
		return this;
	}
	
	@Override
	public IPresenterList prev(Integer nodeType) {
		PresenterList prev = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			prev._add(item.prev(nodeType));
		}
		return prev;
	}
	
	@Override
	public IPresenterList prev() {
		return prev(1);
	}
	
	@Override
	public IPresenterList prevAll(Integer nodeType) {
		PresenterList prevAll = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			prevAll._add(item.prevAll(nodeType));
		}
		return prevAll;
	}

	@Override
	public IPresenterList prevAll() {
		return prevAll(1);
	}
	
	@Override
	public IPresenterList prevUntil(IPresenter until, Integer nodeType) {
		PresenterList prevUntil = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			prevUntil._add(item.prevUntil(until, nodeType));
		}
		return prevUntil;
	}

	@Override
	public IPresenterList prevUntil(IPresenter until) {
		return prevUntil(until, 1);
	}
	
	@Override
	public IPresenterList prop(Property prop, String propValue) {
		return prop(prop.getName(), propValue);
	}
	
	@Override
	public IPresenterList prop(String propName, String propValue) {
		for (IPresenter item : toArray()) item.prop(propName, propValue);
		return this;
	}

	IPresenterList push(IPresenterList previous) {
		_previous = previous;
		return this;
	}

	@Override
	public IPresenterList remove() {
		for (IPresenter item : toArray()) item.remove();
		return this;
	}

	@Override
	public IPresenterList removeAttr(Attribute... attrs) {
		for (IPresenter item : toArray()) item.removeAttr(attrs);
		return this;
	}
	
	@Override
	public IPresenterList removeAttr(String... attrNames) {
		for (IPresenter item : toArray()) item.removeAttr(attrNames);
		return this;
	}

	@Override
	public IPresenterList removeClass(String... classNames) {
		for (IPresenter item : toArray()) item.removeClass(classNames);
		return this;
	}
	
	@Override
	public IPresenterList removeProp(Property prop) {
		return removeProp(prop.getName());
	}
	
	@Override
	public IPresenterList removeProp(String propName) {
		for (IPresenter item : toArray()) item.removeProp(propName);
		return this;
	}

	@Override
	public IPresenterList replaceClass(String oldClassName, String newClassName) {
		for (IPresenter item : toArray()) {
			item.replaceClass(oldClassName, newClassName);
		}
		return this;
	}

	@Override
	public IPresenterList resetClass() {
		for (IPresenter item : toArray()) item.resetClass();
		return this;
	}

	@Override
	public IPresenterList reverse() {
		PresenterList reversed = (PresenterList) new PresenterList().push(this);		
		if (length() > 0) {
			IPresenter[] array = toArray();
			for (int i = length()-1; i>=0; i--) {
				reversed._add(array[i]);
			}
		}
		return reversed;
	}

	@Override
	public IPresenterList scroll() {
		for (IPresenter item : toArray()) item.scroll();
		return this;
	}

	@Override
	public IPresenterList scroll(ScrollHandler handler) {
		return on(handler);
	}
	
	public IPresenterList shallow() {
		return shallow(false);
	}
	
	@Override
	public IPresenterList shallow(Boolean withDataAndEvents) {
		PresenterList shallowed = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) shallowed._add(item.clone(withDataAndEvents));
		return shallowed;
	}
	
	
	@Override
	public IPresenterList show() {
		for (IPresenter item : toArray()) {
			item.show();
		}
		return this;
	}

	@Override
	public IPresenterList siblings(Integer nodeType) {
		PresenterList siblings = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			siblings._add(item.siblings(nodeType));
		}
		return siblings;
	}

	@Override
	public IPresenterList siblings() {
		return siblings(1);
	}
	
	@Override
	public IPresenterList slice(Integer start) {
		return slice(start, length()-1);
	}

	@Override
	public IPresenterList slice(Integer start, Integer end) {
		PresenterList sliced = new PresenterList();
		if (length() > 0) {
			Integer startbak = start, endbak = end;
						
			start = MiscUtils.getZeroBased(start, _items.size());
			end   = MiscUtils.getZeroBased(end,   _items.size());

			if (end == -1) {
				if (endbak > length()-1)  end = length();
				if (endbak < -length())   end = 0;								
			}
			if (start == -1) {
				if (startbak < -length())  start = 0;				
				if (startbak > length()-1) start = length();				
			}

			if (start != end) {
				List<IPresenter> list;
				if (start > end) list = _items.subList(end, start);
				else list = _items.subList(start, end);
				sliced._add((IPresenter[]) list.toArray(new IPresenter[list.size()]));				
			}
			
			if (start > end) sliced = (PresenterList) sliced.reverse();
		}
		return ((PresenterList) sliced).push(this);
	}

	@Override
	public IPresenterList submit() {
		for (IPresenter item : toArray()) item.submit();
		return this;
	}
	
	@Override
	public IPresenterList submit(SubmitHandler handler) {
		return on(handler);
	}
	
	@Override
	public String text() {
		List<String> texts = new ArrayList<String>();
		for (IPresenter item : toArray()) {
			if (item.text() != null) {
				texts.add(item.text());			
			}
		}
		return Strings.join("",(String[]) texts.toArray(new String[texts.size()]));		
	}
	
	@Override
	public IPresenter[] toArray() {
		return (IPresenter[]) _items.toArray(new IPresenter[_items.size()]);
	}
	
	@Override
	public List<IPresenter> toList() {
		return _items;
	}

	@Override
	public IPresenterList toggle() {
		for (IPresenter item : toArray()) {
			item.toggle();
		}
		return this;
	}

	@Override
	public IPresenterList toggleClass(String... classNames) {
		for (IPresenter item : toArray()) {
			item.toggleClass(classNames);
		}
		return this;
	}
	
	@Override
	public IPresenterList trigger(String eventName) {
		for (IPresenter item : toArray()) {
			item.trigger(eventName);
		}
		return this;
	}

	@Override
	//TODO code me	
	public IPresenterList unwrap() {
		PresenterList unwrapped = (PresenterList) new PresenterList().push(this);
		for (IPresenter item : toArray()) {
			unwrapped._add(item.unwrap());			
		}
		return unwrapped;
	}

	@Override
	public IPresenterList width(String value) {
		for (IPresenter item : toArray()) {
			item.width(value);
		}
		return this;
	}

	@Override
	public IPresenterList wrap(IPresenter wrapper) {
		IPresenter clone = wrapper.clone(true, true);
		first().wrap(wrapper);
		for (IPresenter item : neq(0).toArray()) {
			item.wrap(clone.clone(true, true));
		}
		return this;
	}

	@Override
	public IPresenterList wrap(String html) {
		for (IPresenter item : toArray()) item.wrap(html);
		return this;
	}
	
//	@Override
//	public IPresenterList wrapAll(IPresenter wrapper) {
//		return this;
//	}
//
//	@Override
//	public IPresenterList wrapAll(String html) {
//		return null;
//	}
//
//	@Override
//	public IPresenterList wrapInner(IPresenter wrapper) {
//		return this;
//	}
//	
//	@Override
//	public IPresenterList wrapInner(String html) {
//		return null;
//	}
}